Embodiments of the present disclosure relate to anti-tamper computer systems, in particular to methods and systems which can embed protection code into software. Among other things, the protection code helps prevent (and make it more costly) to reverse engineer to tamper with the protected software with malicious intent, such as, but not restricted to: the removal of a license protection mechanism; the removal of code displaying advertisements; the injection of a malicious thread into the program memory space; illicit usage; or any other kind of unauthorized modification of the software.
Some conventional anti-tamper methods include: white-box cryptography techniques; self-checking anti-tamper software; software checks cooperating with a remote server with the purpose of downloading on-demand encrypted and/or authenticated code; software cooperating with a remote server whose goal is to remotely check randomly located or predefined portions of code and/or data; software relying on trusted hardware for ensuring its integrity; etc.
A vast majority of deployed software, notably in embedded systems, cannot rely on a synchronized, bidirectional and permanent communication link with a remote server and/or trusted hardware. Prominent such examples include for instance industrial systems, computers used in the automotive industry, or small computers able to communicate through an ad-hoc network, but without any access to the Internet. Other scenarios include the possibility that such a synchronized and bidirectional communication link with a remote server is too costly in terms of bandwidth and/or energy consumption and/or computational capabilities.
Consequently, one challenge with software tamper-proofing methods that cannot leverage on a continuous bidirectional communication link with a remote server, or on trusted hardware, is to design a method that can withstand the efforts of a reverse engineer as much as possible while requiring only modest computational and memory needs.
Embedding checks into software to be protected, those checks verifying portions of code and data showing dependencies that can be modeled by a Directed Acyclic Graph (DAG), can often be defeated, or made ineffective, as soon as a single check whose location is not covered by at least another check has been identified in the protected software by the reverse engineer. A Directed Acyclic Graph (DAG) is a special kind of graph whose directed edges do not result in any directed loop or cycle. An example of self-checking code whose dependencies can be modeled by a DAG is illustrated in FIG. 2, and the resulting graph is illustrated in FIG. 3. An example of self-checking code whose dependencies form a cycle is illustrated in FIG. 4, and the resulting graph is illustrated in FIG. 5.
The check routines, once their locations have been identified in the protected software, can be themselves modified such that they return always a valid result, even in the case where the software to be protected has been tampered. Some attacks may include identifying check routine locations and replacing, partially or completely, their machine code with inoperative machine instructions, such as a sequence of NOPs (NOP being an abbreviated form of the “No OPeration” machine instruction) on the Intel x86 architecture.
Embodiments of the present disclosure address these and other issues. In some embodiments, the system analyzes dependencies of the checks to form a Directed Graph that explicitly embeds at least one cycle. Result values delivered by the check routines may be used to dynamically compute the starting address of the next sequential block of machine code to be executed at run-time.
The first property helps to ensure that there is no single check routine whose location is not checked itself by at least one other check routine. Hence, a reverse engineer would have to remove all the checks at the same time. The second property helps ensure that, even in the case where all the checks have been removed at the same time, some information, such as the values returned by the checks, will be missing at run-time in order to execute the software as expected by its developers.